package com.kma.ncpractice2013.servlets;




import com.kma.ncpractice2013.auth.Crypto;
import com.kma.ncpractice2013.dao.NonceDAO;
import com.kma.ncpractice2013.dao.UserDAO;
import com.kma.ncpractice2013.model.Nonce;
import com.kma.ncpractice2013.model.User;
import org.expressme.openid.*;

import javax.servlet.ServletConfig;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import javax.servlet.http.HttpSession;
import java.io.IOException;
import java.io.PrintWriter;
import java.sql.Date;
import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.util.UUID;

/**
 * User: Viktor
 * Date: 12/1/13
 */

public class OpenIDServlet extends HttpServlet
{
	static final long ONE_HOUR = 3600000L;
	static final long TWO_HOUR = ONE_HOUR * 2L;
	static final String ATTR_MAC = "openid_mac";
	static final String ATTR_ALIAS = "openid_alias";

	OpenIdManager manager;

	@Override
	public void init(ServletConfig config) throws ServletException {

		super.init(config);
		manager = new OpenIdManager();
		manager.setRealm("http://apptest1.elasticbeanstalk.com/");
		manager.setReturnTo("http://apptest1.elasticbeanstalk.com/openid");
	}

	@Override
	protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
		String op = request.getParameter("op");
		if (op==null) {

			checkNonce(request.getParameter("openid.response_nonce"), response);

			byte[] mac_key = (byte[]) request.getSession().getAttribute(ATTR_MAC);
			String alias = (String) request.getSession().getAttribute(ATTR_ALIAS);
			Authentication authentication = manager.getAuthentication(request, mac_key, alias);
			//String identity = authentication.getIdentity();
			String email = authentication.getEmail();
			UserDAO userDAO = new UserDAO();
			User user = userDAO.getByLogin(email);
			if (user == null)
			{
				Date d = new Date(System.currentTimeMillis());
				String firstName = authentication.getFirstname();
				String lastName = authentication.getLastname();
				user = new User();
				user.setLogin(email);
				user.setName(firstName.length()>0?firstName:email);
				user.setSurname(lastName);
				user.setAccessLevelId(User.AccessLevel.registeredCustomer);
				user.setPhone("");
				user.setSalt(Crypto.generateSalt());
				user.setRegistrationDate(d);
				user.setPassword(Crypto.getHash(user.getSalt(), "", "SHA-256"));
				user.setRegistrationToken(UUID.randomUUID().toString());
				user.setGroupId(User.Group.ordinaryCustomer);
				userDAO.create(user);


			}


				HttpSession sess = request.getSession();
				sess.setAttribute("username", email);
				sess.setAttribute("auth", "true");
				sess.setAttribute("access_level", user.getAccessLevelId().getValue());
				sess.setAttribute("user", user);


				response.sendRedirect("main_page.jsp");

			//showAuthentication(response.getWriter(), identity, email);

		}
		else if ("Google".equals(op)) {

			Endpoint endpoint = manager.lookupEndpoint("Google");
			Association association = manager.lookupAssociation(endpoint);
			request.getSession().setAttribute(ATTR_MAC, association.getRawMacKey());
			request.getSession().setAttribute(ATTR_ALIAS, endpoint.getAlias());
			String url = manager.getAuthenticationUrl(endpoint, association);
			response.sendRedirect(url);
		}
		else {
			response.sendRedirect("/error.jsp");
			throw new ServletException("Bad parameter op=" + op);
		}
	}



	void checkNonce(String nonce, HttpServletResponse response) throws IOException
	{

		if (nonce==null || nonce.length()<20)
		{
			throw new OpenIdException("Verify failed.");
		}
		long nonceTime = getNonceTime(nonce, response);
		long diff = System.currentTimeMillis() - nonceTime;
		if (diff < 0)
			diff = (-diff);
		if (diff > ONE_HOUR)
			response.sendRedirect("/error.jsp");
				//throw new OpenIdException("Bad nonce time.");
		if (isNonceExist(nonce))
			response.sendRedirect("/error.jsp");
				//throw new OpenIdException("Verify nonce failed.");
		storeNonce(nonce, nonceTime + TWO_HOUR);
	}

	boolean isNonceExist(String nonce) {
		NonceDAO nonceDAO = new NonceDAO();
		Nonce nonce_db = nonceDAO.getByNonce(nonce);
		return nonce_db != null;
	}

	void storeNonce(String nonce, long expires) {
		NonceDAO nonceDAO = new NonceDAO();
		Nonce nonce_db = new Nonce();
		nonce_db.setNonce(nonce);
		nonce_db.setExpires(expires);
		nonceDAO.create(nonce_db);
	}

	long getNonceTime(String nonce, HttpServletResponse response) throws IOException
	{
		try {
			return new SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ssZ")
					       .parse(nonce.substring(0, 19) + "+0000")
					       .getTime();
		}
		catch(ParseException e) {
			response.sendRedirect("/error.jsp");
			//	throw new OpenIdException("Bad nonce time.");

		}
		return 0;
	}

}
